using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using DialectSoftware.Web.JsAPI;
using DialectSoftware.Web.UI.CustomUserControls;
using System.Collections.Generic;
using System.ComponentModel;

namespace Demo.UserControls
{
    //TODO:observer : designer : List property support
    /// <summary>
    /// http://wiki.github.com/madrobby/scriptaculous/slider
    /// </summary>
    public partial class SliderControl : UserControlBase, IMultipleModeEventHandler  
    {
        public delegate void SliderChangeHandler(object sender, SliderControlEventArgs args);
        public event SliderChangeHandler OnSliderChange;


        /// <summary>
        /// 
        /// </summary>
        [ClientSideVariable("mode")]
        [Category("Behavior")]
        public ControlMode Mode
        {
            get
            {
                return ViewState["mode"] == null ? ControlMode.Server : (ControlMode)ViewState["mode"];
            }
            set
            {
                ViewState["mode"] = value;
            }

        }

        /// <summary>
        /// Sets the direction that the slider will move in. 
        /// It should either be horizontal or vertical. 
        /// </summary>
        [ClientSideVariable("axis")]
        public String Axis
        {
            get
            {
                return ViewState["axis"] == null ? "horizontal" : (String)ViewState["axis"];
            }
            set
            {
                ViewState["axis"] = value;
            }

        }

        /// <summary>
        /// Will set the initial slider value. 
        /// The handle will be set to this value, 
        /// assuming it is within the minimum and maxium values. 
        /// </summary>
        [ClientSideVariable("value","{0}")]
        public String Value
        {
            get
            {
                return ViewState["string"] == null ? "0" : (String)ViewState["string"];
            }
            set
            {
                ViewState["string"] = value;
            }

        }
        
        /// <summary>
        /// The minimum value that the slider can move to. 
        /// For horizontal this is to the left while vertical it is up. 
        /// Note: this also sets the beginning of the slider (zeroes it out). 
        /// </summary>
        [ClientSideVariable("minimum","{0}")]
        public Int32 Min
        {
            get
            {
                return ViewState["minimum"] == null ? 0 : (Int32)ViewState["minimum"];
            }
            set
            {
                ViewState["minimum"] = value;
            }

        }

        /// <summary>
        /// Length of track in pixels adjusted by increment. 
        /// The maximum value that the slider will move to. 
        /// For horizontal this is to the right while vertical it is down.
        /// </summary>
        [ClientSideVariable("maximum","{0}")]
        public Int32 Max
        {
            get
            {
                return ViewState["maximum"] == null ? 100 : (Int32)ViewState["maximum"];
            }
            set
            {
                ViewState["maximum"] = value;
            }

        }


        /// <summary>
        /// Defines the relationship of value to pixels. 
        /// Setting this to 1 will mean each movement of 1 pixel equates to 1 value.
        /// </summary>
        [ClientSideVariable("increment", "{0}")]
        public Int32 Increment
        {
            get
            {
                return ViewState["increment"] == null ? 1 : (Int32)ViewState["increment"];
            }
            set
            {
                ViewState["increment"] = value;
            }

        }


        [ClientSideVariable("values"),
        JsConverter(typeof(SliderControl.ListConveter))]
        [TypeConverter(typeof(StringArrayConverter))]
        public String[] Values
        {
            get
            {
                if (ViewState["values"] == null)
                    ViewState["values"] = new String[] { };
                return ViewState["values"] as String[];
            }

            set 
            {
                ViewState["values"] = value;
            }
        }

        public String SliderStyle
        {
            get
            {
                return ViewState["slider-style"] == null ? "background-image:url(images/bg-fader.gif); background-repeat:no-repeat; width:209px; height:28px;" : (String)ViewState["slider-style"];
            }
            set
            {
                ViewState["slider-style"] = value;
            }
        }

        public String HandleStyle
        {
            get
            {
                return ViewState["handle-style"] == null ? "background-image:url(images/thumb-n.gif); background-repeat:no-repeat; width:17px; height:21px; cursor:move" : (String)ViewState["handle-style"];
            }
            set
            {
                ViewState["handle-style"] = value;
            }

        }

        protected override void Page_Load(object sender, EventArgs e)
        {

        }

        #region IPostBackEventHandler Members

        public void RaisePostBackEvent(string eventArgument)
        {
            this.Value = eventArgument;
            if (OnSliderChange != null)
            {
                OnSliderChange(this, new SliderControlEventArgs(eventArgument));
            }
        }

        #endregion

        #region ICallbackEventHandler Members

        public string GetCallbackResult()
        {
            return this.Value;
        }

        public void RaiseCallbackEvent(string eventArgument)
        {
            this.Value = eventArgument;

            if (OnSliderChange != null)
            {
                OnSliderChange(this, new SliderControlEventArgs(eventArgument));
            }
        }

        #endregion

        [JsFunction()]
        public JsOperation Change(var value, var sender)
        {
            String cbReference = String.Empty;
            String callbackScript = String.Empty;
            switch (Mode)
            {
                case ControlMode.Server:
                    cbReference = Page.ClientScript.GetPostBackEventReference(this, "$value$", false).Replace("'$value$'", "value");
                    callbackScript = "document.observe('dom:loaded',function(){" + this.OnChange(value, this.GetJsType().ClientID) + "});";
                    callbackScript = "if(this.loaded == false){this.loaded = true;" + callbackScript + "return;} " + cbReference + "";
                    break;
                case ControlMode.Ajax:
                    cbReference = Page.ClientScript.GetCallbackEventReference(this, "value", this.GetJsType().OnChange, this.slider.ClientID);
                    callbackScript = cbReference;
                    break;
                case ControlMode.Client:
                    callbackScript = this.OnChange(value, "this.ID");
                    break;
            }

            function f = new function();
            f.AddOperation(callbackScript);
            return new JsOperation(this, f, value, this.ClientID);
        
        }

        [JsFunction()]
        public JsOperation Slide(var value, var sender)
        {
            String callbackScript = this.OnSlide(value, this.GetJsType().ClientID);
            function f = new function();
            f.AddOperation(callbackScript);
            return new JsOperation(this, f, value, this.ClientID);
        }

        [JsFunction()]
        public JsOperation Initialize()
        {
            string slider = this.slider.ClientID;
            string javascript = 
                 @"this.slider = new Control.Slider('" + slider + @"_handle',
                       '" + slider + @"',                                  
                       {
                        id:'" + slider + @"',
                        axis:this.axis,
                        loaded:false,
                        range:$R(this.minimum,this.maximum,false),
                        increment:this.increment,
                        sliderValue:this.value,
                        values:this.values.length == 0?null:this.values,
                        onChange: " + this.GetJsType().Change + @",
                        onSlide: "  + this.GetJsType().Slide + @"
              });
              " + "this.slider.setValue(" + this.ClientID + @".value);";

            function f = new function();
            f.AddOperation(javascript);
            return new JsOperation(this, f);

        }

        [JsFunction()]
        public JsOperation OnChange(var value, var id)
        {
            function f = new function();
            f.AddOperation("alert('slider control value changed to ' + value)");
            return new JsOperation(this, f, value, id);
        }

        [JsFunction()]
        public JsOperation OnSlide(var value, var id)
        {
            function f = new function();
            f.AddOperation("");
            return new JsOperation(this, f, value, id);
        }

        internal class ListConveter : IJsConverter
        {

            #region IJsConverter Members

            public JsObject Convert(object obj)
            {
                int i = 0;
                String script = "[";
                System.Array.ForEach(((string[])obj), new Action<string>(delegate(string item){
                    if (i == 0)
                    {
                        script += item; 
                    }
                    else
                    { 
                         script += "," + item ;
                    }
                    i++;
                }));
                script += "]";
                return script;
            }

            #endregion
        }
    }


    public class SliderControlEventArgs : System.EventArgs
    {
        String value;

        public String Value
        {
            get { return this.value; }
            set { this.value = value; }
        }

        public SliderControlEventArgs(string value)
        {
            this.value = value;
        }

    }
    
}